#ifndef _MATRIX_HPP_
#define _MATRIX_HPP_

#include <cmath>
#include <iostream>


#include "config.cpp"

#include "vector.hpp"

namespace ALGEBRA
{
    class Matrix
    {
        private:
            real_t  *_m;
            int Size;
            bool _created;

            real_t  _GetElem( int i, int j)
            {
                std::cout << 'i' << i << "\tj" << j << std::endl;
                return _m[ i * Size + j];
            }
            Matrix( )
            {
            }

        public:
            // конструкторы деструкторы
            Matrix( int I)
            {
                _created = false;
                Create( I);
            }

            ~Matrix( )
            {
                Delete( );
            }
            void Create( int N)
            {
                Delete( );
                Size = N;
                _m = new real_t[ Size*Size];
                _created = true;
            }

            void Create( real_t * M, int I)
            {
                Delete( );
                Create ( I);
                for ( int i = 0; i < Size*Size; i++)
                {
                    _m[ i] = M[ i];
                }
            }
            void Delete( )
            {
                if ( _created)
                {
                    delete [] _m;
                    _m = NULL;
                    _created = false;
                }
            }
            ////////////////////////////////////////////////////////////
            /// Строка                 ///
            Vector operator[] ( int I)
            {
                Vector row( I);
                for ( int i = 0; i < Size; i++)
                {
                    row._v[ i] = _m[ I * Size + i];
                }
                return row;
            }

            Matrix GetUp()
            {
                Matrix up;
                for ( int i = 0; i < Size; i++)
                {
                    for( int j = 0; j < Size; j++)
                    {
                        if ( i < j)
                        {
                            up._m[ i * Size + j] = _m[ i * Size + j];
                        }
                    }
                }
                return up;
            }

            real_t GetNorm1( )
            {

            }
            real_t GetNorm2( )
            {

            }
            real_t GetNorm3( )
            {

            }

            /// Сложение|вычитание
            Matrix operator+= ( Matrix const mat)
            {
                for ( int i = 0; i < Size*Size; i++)
                {
                    _m[ i] += mat._m[ i];
                }
                return *this;
            }

            Matrix operator+  ( Matrix const mat)
            {
                Matrix result( mat);

                for ( int i = 0; i < Size*Size; i++)
                {
                    result._m[ i] += _m[ i];
                }
                return result;
            }

            Matrix operator-= ( Matrix const mat)
            {
                for ( int i = 0; i < Size*Size; i++)
                {
                    _m[ i] -= mat._m[ i];
                }
                return *this;
            }


            Matrix operator-  ( Matrix const &mat)
            {
                Matrix result( mat);

                for ( int i = 0; i < Size*Size; i++)
                {
                    result._m[ i] -= _m[ i];
                }
                return result;
            }

            Matrix operator-( )
            {
                Matrix result;

                result._m[0] = -_m[0];
                result._m[1] = -_m[1];
                result._m[2] = -_m[2];

                return result;
            }

            Matrix operator+  ( )
            {
                return *this;
            }

            ///  Произведение
            Matrix operator*= ( const real_t N)
            {
                for ( int i = 0; i < Size*Size; i++)
                {
                    _m[ i] *= N;
                }
                return *this;
            }
            Matrix operator*  ( const real_t N)
            {
                Matrix mat ( *this );

                for ( int i = 0; i < Size*Size; i++)
                {
                    mat._m[ i] *= N;
                }
                return mat;
            }

            Matrix operator* ( const Matrix  mat)
            {
                Matrix res( Size);

                for ( int i = 0; i < Size; i++)
                {
                    for ( int j = 0; j < Size; j++)
                    {
                        for ( int k = 0; k < Size; k++)
                        {
                            res._m[ i * Size + j] += _m[ i * Size + k] * mat._m[ k * Size + j];
                        }
                    }
                }
                return res;
            }

            Vector operator* ( const Vector  vec)
            {
                Vector res( Size);

                for ( int i = 0; i < Size; i++)
                {
                    res._v[ i] = 0;
                    for ( int j = 0; j < Size; j++)
                    {
                        res._v[ i] += _GetElem( i, j) * vec._v[ j];
                    }
                }
                return res;
            }
    }; //class Matrix
} //namespace ALGEBRA
#endif //_MATRIX_HPP_
